/**
 * 
 */
package com.eagle.coders.core.template.handler;

import java.io.StringWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;

import com.eagle.coders.common.ui.form.renderer.ApplicationRenderer;
import com.eagle.coders.common.ui.interfaces.IComponent;
import com.eagle.coders.core.exceptions.BaseAppException;
import com.eagle.coders.core.exceptions.RendererException;
import com.eagle.coders.core.exceptions.TemplateException;
import com.eagle.coders.core.template.handler.util.DomainSorter;
import com.eagle.coders.core.type.TemplateType;
import com.eagle.coders.xml.transformation.Transformer;
import com.eagle.coders.xml.transformation.beans.Actions;
import com.eagle.coders.xml.transformation.beans.DomainLayoutBean;
import com.eagle.coders.xml.transformation.beans.Domains;
import com.eagle.coders.xml.transformation.beans.Row;
import com.eagle.coders.xml.transformation.beans.Usecase;
import com.eagle.coders.xml.transformation.beans.UsecaseResourceBundle;
import com.eagle.coders.xml.transformation.display.beans.DisplayingPolicies;

/**
 * @author Anees
 * 
 */
public class TemplateLoader {

	private static final String WEB_LAYOUT = "/web/dynaFormTemplates.vm";
	private static final String WEB_LAYOUT_NEW = "/web/dynaFormTemplates_old.vm";
	private static final String WEB_BUTTON_LAYOUT = "/web/dynaButtonTemplates.vm";
	private static final String NATIVE_LAYOUT = "./native/DefaultSwingLayout.vm";
	private static final String MY_BATIS_LAYOUT = "/beanMapper/myBatisMapperGenerator.vm";

	private Locale currentAppLocale;
	
	private static TemplateLoader instance;
	private String formOrientation;
	private List<Domains> domainList;
	private DisplayingPolicies displayPolicies;
	private TemplateType templateType;

	private SortedMap<Integer, DomainLayoutBean> domainLayoutMap;
	private String actionLayout;
	private Map<String, Domains> domainPropertyMap;

	private Actions actions;
	
	private String resourceProperties;

	public TemplateLoader(TemplateType templateType, IComponent component) {
		buildLayoutingForUI(templateType, component);
	}
	
	
//	public TemplateLoader(TemplateType templateType, IComponent component, String formOrientation) {
//		this.formOrientation = formOrientation;
//		buildLayoutingForUI(templateType, component);
//	}

	public TemplateLoader(final Locale currentAppLocale, TemplateType templateType, IComponent component, String formOrientation){
		this.formOrientation = formOrientation;
		this.currentAppLocale = currentAppLocale;
		buildLayoutingForUI(templateType, component);
	}
	
	private TemplateLoader() {}

	/**
	 * 
	 * @return
	 */
	public synchronized static TemplateLoader getInstance() {
		if (null == instance)
			instance = new TemplateLoader();
		return instance;
	}

	/**
	 * 
	 * @param templateType
	 * @param component
	 * @return
	 */
	public static TemplateLoader getInstance(TemplateType templateType,
			IComponent component) {
		if (null == instance)
			instance = new TemplateLoader(templateType, component);
		return instance;
	}
	

	/**
	 * 
	 * @param templateType
	 * @param component
	 */
	private void buildLayoutingForUI(TemplateType templateType,
			IComponent component) {
		this.templateType = templateType;
		String usecaseForm = "";
		if(null != component.getXml())
			usecaseForm = component.getXml();
		else{
			ApplicationRenderer applicationRenderer = new ApplicationRenderer();
			usecaseForm = applicationRenderer.generateUsecaseForm(component, false);
		}
		
		Transformer transformer = new Transformer();
		Usecase usecase = transformer.toUsecase(usecaseForm,
				component.getComponentIdentity());
		build(usecase);
	}
	
	/**
	 * 
	 * @param usecase
	 */
	private void build(final Usecase usecase) {
		
		actions = usecase.getActions();
		
		UsecaseResourceBundle usecaseResourceBundle = usecase.getUsecaseResourceBundle();
		
		if(null != usecaseResourceBundle){
			String resourceFileName = usecaseResourceBundle.getFileName();
			System.out.println("[TemplateLoader]{build} :: resourceFileName : "+resourceFileName);
			String resourceFilelocation = usecaseResourceBundle.getFileLocation();
			if("".equals(resourceFilelocation))
				resourceProperties = resourceFileName;
			else
				resourceProperties = resourceFilelocation+"."+resourceFileName;
		}
		

		domainList = usecase.getDomainList();
		displayPolicies = usecase.getDisplayingPolicies();

		domainPropertyMap = new HashMap<String, Domains>();

		domainLayoutMap = getLayout();
	}

	/**
	 * 
	 * @return
	 */
	public String getActionTemplate() throws BaseAppException {
		return getTemplate(TemplateType.WEB_BUTTON, null);
	}

	/**
	 * 
	 * @return
	 */
	public Actions getActions() {
		return this.actions;
	}

	/**
	 * 
	 * @return
	 */
	public DisplayingPolicies getDisplayingPolicies() {
		return this.displayPolicies;
	}

	/**
	 * 
	 * @return
	 */
	public SortedMap<Integer, DomainLayoutBean> getDomainLayoutMap() {
		return this.domainLayoutMap;
	}

	/**
	 * @return the domainPropertyMap
	 */
	public Map<String, Domains> getDomainPropertyMap() {
		return domainPropertyMap;
	}
	
	/**
	 * 
	 * @param locale
	 * @return
	 */
	public ResourceBundle getResourceBundle(Locale locale){
		
		try{
			return ResourceBundle.getBundle(resourceProperties, locale);
		}catch(Exception e){
			return null;
		}
	}
	
	/**
	 * @return the ResourceBundle
	 */
	public ResourceBundle getResourceBundle() {
		try{
			ResourceBundle resourceBundle = null;
			if(null == currentAppLocale)
				resourceBundle= ResourceBundle.getBundle(resourceProperties);
			else
				resourceBundle = ResourceBundle.getBundle(resourceProperties, currentAppLocale);
//			System.out.println("[TemplateLoader]{getResourceBundle()} :: "+resourceBundle);
//			Set<String> keys = resourceBundle.keySet();
//			for(String key : keys){
//				System.out.println("Key :: "+key +" | value :: "+resourceBundle.getString(key));
//			}
			return resourceBundle;
		}catch(Exception e){
//			e.printStackTrace();
			return null;
		}
	}


	/**
	 * 
	 * @param templateType
	 * @param toInject
	 * @return
	 */
	public String getTemplate(TemplateType templateType,
			Map<String, Object> toInject) throws BaseAppException {

		try {
			VelocityReader vr = new VelocityReader();
			if (templateType.toString().equals(TemplateType.MYBATIS.toString())) {
				return vr.render(MY_BATIS_LAYOUT, toInject);
			} else if (templateType.toString().equals(
					TemplateType.WEB_BUTTON.toString())) {
				return vr.render(WEB_BUTTON_LAYOUT, null);
			} else
				return null;
		} catch (TemplateException e) {

			throw new BaseAppException(e.getMessage());
		} catch (RendererException re) {
			throw new BaseAppException(re.getMessage());
		}
	}
	
	/**
	 * 
	 * @param rows
	 * @param domainName
	 * @return
	 */
	public String getLayoutForRows(List<Row> rows, String domainName){
		
		try{
			
			Template template = null;

			VelocityContext context = new VelocityContext();
			VelocityEngine ve = new VelocityEngine();
			ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
			ve.setProperty("classpath.resource.loader.class",
					ClasspathResourceLoader.class.getName());

			ve.init();
			
			if (templateType.equals(TemplateType.WEB)) {
				template = ve.getTemplate(WEB_LAYOUT_NEW);
			}
			
			DomainLayoutBean domainLayoutBean = new DomainLayoutBean();
			domainLayoutBean.setDomainName(domainName);
			
			if(null != this.formOrientation && !"".equals(this.formOrientation)){
				context.put("orientation", this.formOrientation);
			}

			context.put("domainName", domainName);
			context.put("rows", rows);

			StringWriter writer = new StringWriter();
			if (null != template) {
				template.merge(context, writer);
			}
			writer.flush();
			writer.close();
			
			return writer.toString();
		}catch (Exception e) {
			// throw new TemplateException();
//			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 
	 * @param templateType
	 * @param component
	 * @return
	 */
	private SortedMap<Integer, DomainLayoutBean> getLayout() {
		try {
			Template template = null;

			SortedMap<Integer, DomainLayoutBean> domainLayoutMap = new TreeMap<Integer, DomainLayoutBean>();

			Collections.sort(domainList, new DomainSorter());

			VelocityContext context = new VelocityContext();
			VelocityEngine ve = new VelocityEngine();
			ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
			ve.setProperty("classpath.resource.loader.class",
					ClasspathResourceLoader.class.getName());

			ve.init();

			if (templateType.equals(TemplateType.WEB)) {
				template = ve.getTemplate(WEB_LAYOUT);
			}

			for (Domains domain : domainList) {

				domainPropertyMap.put(domain.getName(), domain);

				DomainLayoutBean domainLayoutBean = new DomainLayoutBean();
				domainLayoutBean.setDomainName(domain.getName());
			
				if(null != this.formOrientation && !"".equals(this.formOrientation)){
					context.put("orientation", this.formOrientation);
				}
				context.put("domain", domain);
				StringWriter writer = new StringWriter();
				if (null != template) {
					template.merge(context, writer);
				}
				writer.flush();
				writer.close();
				domainLayoutBean.setLayout(writer.toString());
				domainLayoutMap.put(Integer.parseInt(domain.getPosition()),
						domainLayoutBean);
//				System.out.println(domain.getName() + "| template \n"
//						+ writer.toString());
			}
			return domainLayoutMap;
		} catch (Exception e) {
			// throw new TemplateException();
			return null;
		}
	}

	// /**
	// *
	// * @param templateType
	// * @return
	// */
	// public String getLayout(TemplateType templateType, String xmlLayout)
	// throws Exception {
	//
	// try {
	// // renderXML(xmlLayout);
	// Template template = null;
	//
	// VelocityContext context = new VelocityContext();
	// VelocityEngine ve = new VelocityEngine();
	// ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
	// ve.setProperty("classpath.resource.loader.class",
	// ClasspathResourceLoader.class.getName());
	//
	// ve.init();
	//
	// // String file =
	// TemplateLoader.class.getClassLoader().getResource(WEB_LAYOUT).getFile();
	// if(templateType.equals(TemplateType.WEB)){
	// template = ve.getTemplate(WEB_LAYOUT);
	// }
	//
	// StringWriter writer = new StringWriter();
	// if(null != template){
	// template.merge(context, writer);
	// }
	// writer.flush();
	// writer.close();
	// return writer.toString();
	// } catch (Exception e) {
	// throw e;
	// }
	// }

	// private static void renderXML(String xml){
	//
	// XStream xstream = new XStream(new DomDriver());
	// xstream.alias("map", Map.class);
	//
	// Map<String,Object> map2 = (Map<String,Object>) xstream.fromXML(xml);
	//
	// System.out.println(" Map : from XML \n"+map2);
	// }
}
